/** \file   TripleP.g
*   \brief  Defintion of TripleP's grammar 
*   \author Ameen Jaber
*   \author Mohamad Noureddine
*   \author Mohamed Sabra
*   \date   27-5-2011
*/

grammar TripleP;

options 
{
    backtrack	= true;
    memoize   	= true;
    k	    	= 3;
    language	= C;
}

@lexer::header
{
 #define	ANTLR3_INLINE_INPUT_ASCII
}

@parser::includes
{
 #include "util.h"
 #include "defs.h"
 #include "actions.h"
 #include "TPType.h"
 #include "InDGraph.h"
 #include <iostream>
 #include <string>
 #include <map>
}

@members 
{
 TPGraph_t * Tgraph; //!< Parse Graph pointer
 TPTable_t * Ttable; //!< Variables table pointer
 revTPTable_t * revTtable; //!< reverse Variables table pointer
 TypeTable_t * Typetable; //!< Table holding canonical name to type constructs <type name> --> <type construct> 
 TypeTable_t * name_Typetable; //!< Table holding type names to type constructs <type_name> --> <type construct>
 VariableTable_t * vTable; //!< Hash table between variable name and type construct. 
 GraphTable_t * gTable; //!< Hash table between the variable name and Graph construct
 algMap_t * aMap; //!< hash map between the variable name and the algorithm
 int type_count = 1; //!< The count of types = the id counter. 
 TPType * intType; //!< A global Integer type to be used by everyone. 
}

/////////// PARSER RULES //////////////
translation_unit returns [TPGraph_t * rgraph, TPTable_t * rTtable,  revTPTable_t * rrevTtable, TypeTable_t * rTypetable, TypeTable_t * rname_Typetable, VariableTable_t * rvTable, GraphTable_t * rgTable, algMap_t * raMap]
@init {
            int count = 1; // Edge count
            int rootid; // The id of the root node
            Tgraph = new TPGraph_t(0);
            Ttable = new TPTable_t();
            revTtable = new revTPTable_t();
            Typetable = new TypeTable_t();
            name_Typetable = new TypeTable_t();
            vTable = new VariableTable_t();
            gTable = new GraphTable_t();
            aMap = new algMap_t();
            rootid = tunit_initialize(Tgraph); // Initialize parsing
        }
@after {
            $rgraph = Tgraph;
            $rTtable = Ttable;
            $rrevTtable = revTtable;
            $rTypetable = Typetable;
            $rname_Typetable = name_Typetable;
            $rvTable = vTable;
            $rgTable = gTable;
            $raMap = aMap;
        }
    : (a = statementList {
            tunit_updateroot(Tgraph, rootid, $a.vid, count);
            count++;
            })+ 
    ;

statementList returns [int vid]
    : t = typeDeclaration {$vid = $t.vid;}
    | d = declaration {$vid = $d.vid;}
    | b = falgorithm {$vid = $b.vid;}
    | e = expression {$vid = $e.vid;}
    ;

// Regular Declaration 
declaration returns [int vid]
    : t=type i=IDENTIFIER ';' { // Integer x //
            char * s = new char[$i.text->len];
            sprintf(s,"\%s",$i.text->chars); 
            std::string index(s); // get the variable name
            delete [] s;    

            TPTable_t::iterator it;
            it = Ttable->find(index);
            if (it != Ttable->end()) {
                std::cerr << "Variable " << index << " already defined\n";
                exit(-1);
            }

            int tid = int_update(Tgraph); // add new integer node to graph and return node id        

            // add the variable to the variable table 
            (*Ttable)[index] = tid;
            // add the variable to the reverse variable table
            (*revTtable)[tid] = index;
            // return -1 in order not to create a new edge
            $vid=-1; 
        }
    | ct = composedtype {$vid = $ct.vid;}
    | c = custom_declaration {$vid = $c.vid;}
    ;

// Custom Declarations 
custom_declaration returns [int vid]
@init {
    bool found = false;
    std::string type_name;
}
    : t=IDENTIFIER {
            char * s = new char[$t.text->len];
            sprintf(s,"\%s",$t.text->chars); 
            std::string index(s); // get the variable name
            delete [] s; 

            // index is the type name, search for it in the table 
            TypeTable_t::iterator it;
            it = name_Typetable->find(index);
            if (it == name_Typetable->end()) { // not found            
                    std::cerr << "Type " << index <<" not defined!\n";
                    exit(-1);
            } else {
                    found = true;
                    type_name = index;
            }    
        } 
        v=IDENTIFIER {
            char * l = new char[$v.text->len];
            sprintf(l,"\%s",$v.text->chars); 
            std::string vname(l); // get the variable name
            delete [] l;

            if (found) { //  found the type 
                int cid = custom_update(Tgraph); // create a new node for this variable
                (*Ttable)[vname] = cid; // update the variable to node id map
                (*revTtable)[cid] = vname; // update the node id to variable map 
                (*vTable)[vname] = (*name_Typetable)[type_name]; // update the hash table 
              //  std::cout << "Variable " << vname << " is of type " << (*vTable)[vname]->get_hashkey() << std::endl;
                $vid = -1; // return -1 in order not to create an edge to the root
            }
        } 
        ';' // Vector v1 check for availability in actions//
    ;

// Expressions
expression returns [int vid]
    : a = assignment_expression {$vid = $a.vid;}
    | i = iterator_expression {$vid = $i.vid;}
    | e = equality_expression {$vid = $e.vid;}
    | c = conditional_expression {$vid = $c.vid;}
    | w = while_expression {$vid = $w.vid;}
    ;

assignment_expression returns [int vid]
    : l=lvalue '=' r=rvalue ';' {// lvalue = rvalue 
            $vid = assignment_update(Tgraph, $l.vid, $r.vid);
        }
    ;

lvalue returns [int vid]
    : i=IDENTIFIER {
            char * s = new char[$i.text->len];
            sprintf(s,"\%s",$i.text->chars); 
            std::string index(s); // get the variable name
            delete [] s;

            int id = lvalue_id(Ttable,  index);
            if (id != -1) { // identifier found
                $vid = id;
            } else {// not found, exit with error
                std::cerr << "Identifier " << index << " not found\n" << std::endl;
                exit(-1);
            }
        }
    | IDENTIFIER 'at' IDENTIFIER
    | function_expression
    ;

rvalue returns [int vid]
    : a = additive_expression {$vid = $a.vid;}
    | r = relation_set_expression {$vid = $r.vid;}
    | f = function_expression
    ;

additive_expression returns [int vid]
    : m = multiplicative_expression {$vid = $m.vid;} ('+' pm = multiplicative_expression {
                int pid = additive_update(Tgraph, $m.vid, $pm.vid, 1); // + = 1
                $vid = pid; // return the id of the + node
            }
        | '-' mm = multiplicative_expression {
                int mid = additive_update(Tgraph, $m.vid, $mm.vid, 2); // - = 2
                $vid = mid; // return the id of the - node 
            }
        )*
    | '(' a = additive_expression ')' {$vid = $a.vid;}
    ;

multiplicative_expression returns [int vid]
    : p = power_expression {$vid = $p.vid;}
        ( '*' mp = power_expression {
                // create a multiplication node 
                int mid = multiplicative_update(Tgraph, $p.vid, $mp.vid, 1); // * = 1
                $vid = mid;
            }
        | '/' mp = power_expression {
                // create a division node 
                int mid = multiplicative_update(Tgraph, $p.vid, $mp.vid, 2); // / = 2
                $vid = mid;
            }
        | 'mod' mp = power_expression {
                // create a modulo node 
                int mid = multiplicative_update(Tgraph, $p.vid, $mp.vid, 3); // mod = 3
                $vid = mid;
            }
        )*
    ;

power_expression returns [int vid]
    : c = cast_expression {$vid = $c.vid;}
        ('^' pc = cast_expression {
                // create exponentiation node
                int pid = power_update(Tgraph, $c.vid, $pc.vid);
                $vid = pid;
            }
        )*
    ;

cast_expression returns [int vid]
@init {
    int unary = 0;
}
    : (u = unary_operator {unary = 1;})? p = postfix_expression {
            if (unary) {
                // A unary operator exists
                int uid = cast_update(Tgraph, $p.vid, $u.type);
                $vid = uid;
            } else {
                $vid = $p.vid;
            }
        }
    ;

postfix_expression returns [int vid]
    : p = primary_expression {$vid = $p.vid;} ('at' a = additive_expression {
            int aid = postfix_update(Tgraph, $p.vid, $a.vid);
            $vid = aid;
        }
        )?
    ; 

primary_expression returns [int vid]
    : i = IDENTIFIER {
            char * s = new char[$i.text->len];
            sprintf(s,"\%s",$i.text->chars); 
            std::string index(s); // get the variable name
            delete [] s;

            int id = lvalue_id(Ttable, index);
            if (id != -1) { // identifier found
                $vid = id;
            } else {// not found, exit with error
                std::cerr << "Identifier " << index << " not found\n" << std::endl;
                exit(-1);
            }
        }
    | e = CONSTANT {
            char * t = new char [$e.text->len];
            sprintf(t,"\%s",$e.text->chars); 
            int value = atoi(t);
            delete [] t;
            
            $vid = create_constant(Tgraph, value);
        }
    | '(' equality_expression ')'
    | '{' additive_expression (',' additive_expression)* '}' // assignment for sequences 
    | '{' '(' additive_expression ':' additive_expression ')' (',' '(' additive_expression ':' additive_expression ')')* '}'
    ;

unary_operator returns [int type]
    : '+' {$type = 1; /* + */ }
    | '-' {$type = 2; /* - */ }
    | '~' {$type = 3; /* ~ */ }
    ;

iterator_expression returns [int vid]
@init{
    int for_id = iterator_create(Tgraph);
    int count = 1;
}
@after {
    $vid = for_id;
}
    : 'foreach' 'element' i1 = IDENTIFIER {
            char * s = new char[$i1.text->len];
            sprintf(s,"\%s",$i1.text->chars); 
            std::string index(s); // get the variable name
            delete [] s;
            int i1_id = iterator_check(Ttable, index);  
            if (i1_id == -1) {
                std::cerr<<"Identifier "<<index<<" not found!";
                exit(-1);
            } else {
                // create edge and connect to for_id 
                int cond = iterator_connect(Tgraph, for_id, i1_id, count);
                if (cond == -1) {
                    std::cerr << "Cannot complete parsing!";
                    exit(-1);
                } else {
                    count++; 
                }
            }
        }
        'in' i2 = IDENTIFIER {
            char * s = new char[$i2.text->len];
            sprintf(s,"\%s",$i2.text->chars); 
            std::string index(s); // get the variable name
            delete [] s;

            int i2_id = iterator_check(Ttable, index);  
            if (i2_id == -1) {
                std::cerr<<"Identifier "<<index<<" not found!";
                exit(-1);
            } else {
                // create edge and connect to for_id 
                int cond = iterator_connect(Tgraph, for_id, i2_id, count);
                if (cond == -1) {
                    std::cerr<<"Cannot complete parsing!";
                    exit(-1);
                } else {
                    count++; 
                }
            }
        }
        'iterating' i3 = IDENTIFIER {
            char * s = new char[$i3.text->len];
            sprintf(s,"\%s",$i3.text->chars); 
            std::string index(s); // get the variable name
            delete [] s;
            
            int i3_id = iterator_check(Ttable, index);  
            if (i3_id == -1) {
                std::cerr <<"Identifier "<< index <<" not found!";
                exit(-1);
            } else {
                // create edge and connect to for_id 
                int cond = iterator_connect(Tgraph, for_id, i3_id, count);
                if (cond == -1) {
                    std::cerr << "Cannot complete parsing!";
                    exit(-1);
                } else {
                    count++; 
                }
            }
        }
        (e = expression  {
                int eid = iterator_connect(Tgraph, for_id, $e.vid, count);
                if (eid == -1) {
                    std::cerr << "Cannot complete parsing!";
                    exit(-1);
                } else {
                    count++;
                }
            }
        | d = declaration {
                //No edge is needed in this case - but should we deal with scopes????!!!!!!!!!!
            }
        | a = falgorithm {
            }
        )*
        'end' ';'
    ;

relation_set_expression returns [int vid]
    : ls = scast_expression {$vid = $ls.vid;} (c = set_operation rs = scast_expression {
                int sid = relation_set_update(Tgraph, $ls.vid, $c.type, $rs.vid);
                $vid = sid;
            }
        )*
    ;

scast_expression returns [int vid]
@init {
   int uid = -1; // id of unary operator if any 
}
    : (u = unary_set_operator {
                uid = scast_create(Tgraph); // create a new unary operator node 
            }
        )?  s = spostfix_expression {
                if (uid == -1) {
                    // no unary operator
                    $vid = $s.vid;
                } else {
                    int cond = scast_connect(Tgraph, uid, $s.vid);
                    if (cond == -1) {
                        std::cerr << "Cannot complete parsing\n";
                        exit(-1);
                    } else {
                        $vid = uid;
                    }
                }
            }
    ;

spostfix_expression returns [int vid]
    : i = IDENTIFIER {
            char * s = new char[$i.text->len];
            sprintf(s,"\%s",$i.text->chars); 
            std::string index(s); // get the variable name
            delete [] s;
            
            int id = spostfix_check(Ttable, Tgraph, index);
           
            if (id == -1) {
                std::cerr << "Identifier " << index << " not found!\n";
                exit(-1);
            } else if (id == -2) {
                std::cerr << "Identifier " << index << " is not a set\n";
                exit(-1);
            } else {
                $vid = id;
            }
        }
    | '(' r = relation_set_expression ')' {$vid = $r.vid;}
    | 'cardinality' 'of' e = relation_set_expression {
            int id = cardinality_update(Tgraph, $e.vid);
            $vid = id;
        }
    ;

set_operation returns [int type]
    : 'union' {$type = Union;}
    | 'intersection' {$type = Intersection;}
    ;

unary_set_operator returns [int type]
    : 'not' {$type = sNot;}
    ;

function_expression
    : IDENTIFIER 'of' rvalue
    ;

equality_expression returns [int vid]
    : el = logical_or_expression {$vid = $el.vid;} ('equals' er = logical_or_expression {
                $vid = equality_update(Tgraph, $el.vid, $er.vid);
            }
        )? 
    ;

logical_or_expression returns [int vid]
    : ll = logical_and_expression {$vid = $ll.vid;} ('or' rl = logical_and_expression {
                $vid = logical_or_update(Tgraph, $ll.vid, $rl.vid);
            }
        )*
    ;

logical_and_expression returns [int vid]
    : rl = relational_expression {$vid = $rl.vid;} ('and' rr = relational_expression {
                $vid = logical_and_update(Tgraph, $rl.vid, $rr.vid);
            }
        )*
    ;

relational_expression returns [int vid]
    : al = additive_expression {$vid = $al.vid;} (c = comparison_operator ar = additive_expression {
                $vid = relational_update(Tgraph, $al.vid, $ar.vid, (TP_Op_t)$c.type);
            }
        )*
    ;

comparison_operator returns [int type]
    : '<'  {type = LessThan;} 
    | '>'  {type = GreaterThan;} 
    | '<=' {type = LessThanEqual;} 
    | '>=' {type = GreaterThanEqual;} 
    ;


// conditional expression
conditional_expression returns [int vid]
@init {
    int if_id = conditional_create(Tgraph, 1); // create a new node for the expression 
    int then_id, else_id; 
    int count = 1; // edge count 
    int tcount = 1; // then edge count
    int ecount = 1; // else edge count
}
@after {
    $vid = if_id;
}
    : 'if' '(' e = equality_expression {
                // connect this expression to the if node 
                int cond = conditional_connect(Tgraph, if_id, $e.vid, count);
                if(cond == -1) {
                    std::cerr << "Cannot complete parsing\n"; // Update the error reporting
                    exit(-1);
                } else {
                    count++;
                }
            } 
        ')' 'then' {
                // connect then node the the if node          
                then_id = conditional_create(Tgraph, 2);
                int cond = conditional_connect(Tgraph, if_id, then_id, count);
                if(cond == -1) {
                    std::cerr << "Cannot complete parsing\n"; // Update the error reporting
                    exit(-1);
                } else {
                    count++;
                }
            } 
        (s1 = expression {
                int cond = conditional_connect(Tgraph, then_id, $s1.vid, tcount);
                if (cond == -1){
                    std::cerr << "Cannot complete parsing\n";
                    exit(-1);
                } else {
                    tcount++;
                }
            } 
        | s2 = declaration {
                int cond = conditional_connect(Tgraph, then_id, $s2.vid, tcount);
                if (cond == -1) {
                    std::cerr << "Cannot complet parsing\n";
                    exit(-1);
                } else {
                    tcount++;
                }
            } 
        | s3 = falgorithm)* 
        ('else' {
                else_id = conditional_create(Tgraph, 3); // create else node 
                int cond = conditional_connect(Tgraph, if_id, else_id, count);
                if (cond == -1) {
                    std::cerr << "Cannot complete parsing\n";
                    exit(-1);
                } else {
                    count++;
                }
            }
        (e1 = expression {
                int cond = conditional_connect(Tgraph, else_id, $e1.vid, ecount);
                if (cond == -1) {
                    std::cerr << "Cannot complete parsing\n";
                    exit(-1);
                } else {
                    ecount++;
                }  
            } 
        | e2 = declaration {
                // No edge is created for declarations (should consider removing it)
            }
        | e3 = falgorithm)* )?
            'end' ';'
    ;

while_expression returns [int vid]
@init {
    int w_id = while_create(Tgraph); // create a while node
    int count = 1;
}
@after {
    $vid = w_id;
}
    : 'continue' 'until' '(' e = equality_expression { 
            int cond = while_connect(Tgraph, w_id, $e.vid, count);
            if(cond == -1) {
                std::cerr << "Cannot complete parsing!\n";
                exit(-1);
            } else {
                count++;
            }
        } 
    ')'  (s1 = expression {
            int cond = while_connect(Tgraph, w_id, $s1.vid, count);
            if(cond == -1) {
                std::cerr << "Cannot complete parsing\n";
                exit(-1);
            } else {
                count++;
            }
        } 
    | s2 = declaration | s3 = falgorithm)* 'end' ';'
    ;

// Algorithm Declaration 
falgorithm returns [int vid]
@init {
    int pid;
    std::string name;
}
@after {
    (*aMap)[name] = $a.ret;
    $vid = pid;
}
    : a=algorithmid  b=IDENTIFIER {
          char * s = new char[$b.text->len];
          sprintf(s,"\%s",$b.text->chars); 
          std::string index1(s); // get the variable name
          name = index1;
          delete [] s;
            
          // check if this variable exists and its type 
          algMap_t::iterator _it;
          _it = aMap->find(index1);
          if (_it == aMap->end()) {
              pid = add_vertex(*Tgraph); // Add graph node
              (*Tgraph)[pid].op = Algorithm;
              (*Ttable)[index1] = pid;
              (*revTtable)[pid] = index1;
          } else {
              std::cerr << "Algorithm " << index1 << " already declared\n";
              exit(-1);
          }
          $a.ret->name = index1;
        } '(' c=IDENTIFIER {
            ////////////////// Get the graph ////////////////
            char * s1 = new char[$c.text->len];
            sprintf(s1,"\%s",$c.text->chars); 
            std::string index(s1); // get the variable name
            delete [] s1;

            // check if this variable exists and its type 
            GraphTable_t::iterator it;
            it = gTable->find(index);
            if (it == gTable->end()) {
                std::cerr << "graph " << index << " not declared\n";
                exit(-1);
            } else {
                // check the variable's type 
                int vid = (*Ttable)[index];
                
                if ((*Tgraph)[vid].op == Graph) {
                    bool condition;
                    TPGraph_t::edge_descriptor e;
                    tie(e, condition) = add_edge(vid, pid, *Tgraph);
                    (*Tgraph)[e].label = 1; // first left neighboor
                }
                $a.ret->gname = index;
            }
        } (',' (d=IDENTIFIER |e=CONSTANT {
            char * t = new char [$e.text->len];
            sprintf(t,"\%s",$e.text->chars); 
            int value = atoi(t);
            delete [] t;

            $a.ret->val_to_start = value;
        }))* ')' ';'
    | algorithmid IDENTIFIER '(' ')' ';'
    ;

algorithmid returns [_algorithm * ret]
@init{ 
    _algorithm * myalg = new _algorithm();
}
@after {
    $ret = myalg;
}
    : 'ExtendSequence' // extending a sequence
    | 'RemoveElement' // removing an element
    | 'AlgAddVector'  // add two vectors 
    | 'AlgSortSequence'  // sorting a vector 
    | 'AlgDotProduct' // dot product
    | 'AlgVMultiply' // multiply
    | 'AlgVDivision' // Division
    | 'AlgSubVector' // subtraction
    | 'AlgVSearch' // Searching
    | 'ReplaceElment' // Replace an element in a sequence
    | 'GraphBFS' {
            myalg->algid = Gbfs;
        } // Graph BFS
    | 'GraphMST' {
            myalg->algid = Gmst;
        }// Graph MST
    | 'Print' // Printing
    ;

/* Declare a new type */
typeDeclaration returns[int vid] 
    : 'DeclareType' c=custype i=IDENTIFIER ';' { // DeclareType Sequence of Integer Vector
            char * s = new char[$i.text->len];
            sprintf(s,"\%s",$i.text->chars); 
            std::string index(s); // get the variable name
            delete[] s;

            $c.subtype->type_name = index; // set the custom type name

            // Update tables
            (*Typetable)[$c.subtype->get_hashkey()] = $c.subtype;
            (*name_Typetable)[$c.subtype->get_name()] = $c.subtype;
            $vid = -1; // return -1 so that root does not add an edge
        }
    ; 

custype returns [TPType * subtype]
@init {
    TPType * custom_type = new TPType();
    custom_type->id = type_count++; // assign id and update the id counter
}
@after {
    $subtype = custom_type;
   // std::cout << custom_type->get_hashkey() << std::endl;
}
    : 'Sequence' 'of' (c = custype {
                    custom_type->_t1 = $c.subtype; // assign subtype to the current construct
                    custom_type->type = Sequence; // update the type of the construct to be a sequence
                }
        | type {
                    if (intType == NULL) { // no type construct available 
                        intType = new TPType(type_count, "Integer", Integer);
                        type_count++; // update the type ids
                    }
                    custom_type->_t1 = intType; // assign subtype 1 to integer
                    custom_type->type = Sequence; // update the type of the construct to be a sequence
        }  
        )
    | 'Set' 'of' (c = custype {
                custom_type->_t1 = $c.subtype; // assign subtype to the current construct
                custom_type->type = Set; // update the type of the construct to be a sequence
            } 
        | type {
                    if (intType == NULL) { // no type construct available 
                        intType = new TPType(type_count, "Integer", Integer);
                        type_count++; // update the type ids
                    }
                    custom_type->_t1 = intType; // assign subtype 1 to integer
                    custom_type->type = Set; // update the type of the construct to be a sequence
            }
        )
    | 'Relation' 'from' i1=IDENTIFIER {
            char * s = new char[$i1.text->len];
            sprintf(s,"\%s",$i1.text->chars); 
            std::string index(s); // get the variable name
            delete [] s;
                
            // check if this variable exists and its type 
            TPTable_t::iterator it;
            it = Ttable->find(index);
            if (it == Ttable->end()) {
                std::cerr << "Variable " << index << " not declared\n";
                exit(-1);
            } else {
                // check the variable's type 
                int variable_id = (*Ttable)[index];
                if ((*Tgraph)[variable_id].op == Integer) {
                    std::cerr << "Cannot declare a relation from a Integer type!" << std::endl;
                    exit(-1);
                } else { // not an integer
                    // get the variables type 
                    TPType * t = (*vTable)[index];
                    custom_type->_t1 = t; // update the first subtype from _t1 to _t2
                }
            }
        } 
        'to' i2=IDENTIFIER {
            char * s = new char[$i2.text->len];
            sprintf(s,"\%s",$i2.text->chars); 
            std::string index(s); // get the variable name
            delete [] s;
                
            // check if this variable exists and its type 
            TPTable_t::iterator it;
            it = Ttable->find(index);
            if (it == Ttable->end()) {
                std::cerr << "Variable " << index << " not declared\n";
                exit(-1);
            } else {
                // check the variable's type 
                int variable_id = (*Ttable)[index];
                if ((*Tgraph)[variable_id].op == Integer) {
                    std::cerr << "Cannot declare a relation to a Integer type!" << std::endl;
                    exit(-1);
                } else { // not an integer
                    // get the variables type 
                    TPType * t = (*vTable)[index];
                    custom_type->_t2 = t; // update the first subtype from _t1 to _t2
                    custom_type->type = Relation;
                }
            }
        }
    | 'Function' 'from' i1=IDENTIFIER {
            char * s = new char[$i1.text->len];
            sprintf(s,"\%s",$i1.text->chars); 
            std::string index(s); // get the variable name
            delete [] s;
                
            // check if this variable exists and its type 
            TPTable_t::iterator it;
            it = Ttable->find(index);
            if (it == Ttable->end()) {
                std::cerr << "Variable " << index << " not declared\n";
                exit(-1);
            } else {
                // check the variable's type 
                int variable_id = (*Ttable)[index];
                if ((*Tgraph)[variable_id].op == Integer) {
                    std::cerr << "Cannot declare a relation from a Integer type!" << std::endl;
                    exit(-1);
                } else { // not an integer
                    // get the variables type 
                    TPType * t = (*vTable)[index];
                    custom_type->_t1 = t; // update the first subtype from _t1 to _t2
                }
            }
        } 
        'to' i2=IDENTIFIER {
            char * s = new char[$i2.text->len];
            sprintf(s,"\%s",$i2.text->chars); 
            std::string index(s); // get the variable name
            delete [] s;
                
            // check if this variable exists and its type 
            TPTable_t::iterator it;
            it = Ttable->find(index);
            if (it == Ttable->end()) {
                std::cerr << "Variable " << index << " not declared\n";
                exit(-1);
            } else {
                // check the variable's type 
                int variable_id = (*Ttable)[index];
                if ((*Tgraph)[variable_id].op == Integer) {
                    std::cerr << "Cannot declare a relation to a Integer type!" << std::endl;
                    exit(-1);
                } else { // not an integer
                    // get the variables type 
                    TPType * t = (*vTable)[index];
                    custom_type->_t2 = t; // update the first subtype from _t1 to _t2
                    custom_type->type = Function;
                }
            }
        }
    ;

// Basic Types 
type returns [int type]
    : 'Integer' {
            $type = (int)Integer;
        }
	;

composedtype returns [int vid]
@init {
    int pid;
}
@after {
    $vid = pid;
}
    : a = type_id b = IDENTIFIER '(' c = IDENTIFIER ',' d = IDENTIFIER ',' e = IDENTIFIER ')' {
            
            char * s = new char[$b.text->len];
            sprintf(s,"\%s",$b.text->chars); 
            std::string index1(s); // get the variable name
            delete [] s;
            
            // check if this variable exists and its type 
            GraphTable_t::iterator _it;
            _it = gTable->find(index1);
            if (_it == gTable->end()) {
                pid = add_vertex(*Tgraph); // Add graph node
                (*Tgraph)[pid].op = Graph;
                (*Ttable)[index1] = pid;
                (*revTtable)[pid] = index1;
            } else {
                std::cerr << "Graph " << index1 << " already declared\n";
                exit(-1);
            }
            ////////////////// Get the Vertices ////////////////
            char * s1 = new char[$c.text->len];
            sprintf(s1,"\%s",$c.text->chars); 
            std::string index(s1); // get the variable name
            delete [] s1;
             
            // check if this variable exists and its type 
            TPTable_t::iterator it;
            it = Ttable->find(index);
            if (it == Ttable->end()) {
                std::cerr << "Variable " << index << " not declared\n";
                exit(-1);
            } else {
                // check the variable's type 
                int vid = (*Ttable)[index];
                //std::cout<<"########"<<(*Tgraph)[vid].op<<std::endl;
                if ((*Tgraph)[vid].op == Custom) {
                    bool condition;
                    TPGraph_t::edge_descriptor e;
                    tie(e, condition) = add_edge(vid, pid, *Tgraph);
                    (*Tgraph)[e].label = 1; // first left neighboor
                }
                //TypeTable_t::iterator ite;
                //ite = name_Typetable->find(index);
                $a.type->V = (*vTable)[index];
                $a.type->V_name = index;
            }
            ////////////////// Get the Edges /////////////////
            char * s2 = new char[$d.text->len];
            sprintf(s2,"\%s",$d.text->chars); 
            std::string index2(s2); // get the variable name
            delete [] s2;
             
            // check if this variable exists and its type 
            TPTable_t::iterator it1;
            it1 = Ttable->find(index2);
            if (it == Ttable->end()) {
                std::cerr << "Variable " << index2 << " not declared\n";
                exit(-1);
            } else {
                // check the variable's type 
                int eid = (*Ttable)[index2];
                if ((*Tgraph)[eid].op == Custom) {
                    bool condition2;
                    TPGraph_t::edge_descriptor e1;
                    tie(e1, condition2) = add_edge(eid, pid, *Tgraph);
                    (*Tgraph)[e1].label = 2; // second left neighboor
                }
                $a.type->E = (*vTable)[index2];
                $a.type->E_name = index2;
            }
            ///////////////// Get the Weights //////////////////
            char * s3 = new char[$e.text->len];
            sprintf(s3,"\%s",$e.text->chars); 
            std::string index3(s3); // get the variable name
            delete [] s3;
             
            // check if this variable exists and its type 
            TPTable_t::iterator it2;
            it2 = Ttable->find(index3);
            if (it2 == Ttable->end()) {
                std::cerr << "Variable " << index << " not declared\n";
                exit(-1);
            } else {
                // check the variable's type 
                int fid = (*Ttable)[index3];
                if ((*Tgraph)[fid].op == Custom) {
                    bool condition3;
                    TPGraph_t::edge_descriptor e2;
                    tie(e2, condition3) = add_edge(fid, pid, *Tgraph);
                    (*Tgraph)[e2].label = 3; // first left neighboor
                }
                $a.type->W = (*vTable)[index3];
                $a.type->W_name = index3;
            }
            (*gTable)[index1] = $a.type; // Add graph construct to the table

        }';' 
    ;

type_id returns [InDGraph * type]
@init {
    InDGraph * ingraph = new InDGraph();
}
@after {
    $type = ingraph;
}
    : 'Graph' {
            ingraph->id = Graph;
        }
    | 'Tree' {
            ingraph->id = Tree;
        }
    ;

/////////////////// LEXER RULES //////////////////////
CONSTANT 
    : DECIMAL_LITERAL
    ;

// Basics 
IDENTIFIER
    : LETTER (LETTER | '0'..'9')*
    ;

fragment 
LETTER
    : '$'
    | 'A'..'Z'
    | 'a'..'z'
    | '_'
    ;

fragment
DECIMAL_LITERAL 
    : ('0' | '1'..'9' '0'..'9'*);

WS  :  (' '|'\r'|'\t'|'\u000C'|'\n') {$channel=HIDDEN;}
    ;
